//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ListLigandEpitopeAlignment.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <fstream>

#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT           10000
#define DEFAULTMISSINGVALUE -100
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
typedef struct PairWise {
  
  String* ligand1;
  String* ligand2;
  
} PairWise;

//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace LigandEpitopeSpace {
  
  bool EqualPairWiseLigand (TNode <LigandEpitopeAlignment>* ligandEpitopeAlignments, void* ref) {

    if (!strcmp(ligandEpitopeAlignments->Info()->LigandName1()->Out(), ((PairWise*)ref)->ligand1->Out())  && 
        !strcmp(ligandEpitopeAlignments->Info()->LigandName2()->Out(), ((PairWise*)ref)->ligand2->Out()))
      return true;
    
    if (!strcmp(ligandEpitopeAlignments->Info()->LigandName1()->Out(), ((PairWise*)ref)->ligand2->Out())  && 
        !strcmp(ligandEpitopeAlignments->Info()->LigandName2()->Out(), ((PairWise*)ref)->ligand1->Out()))
      return true;
    
    return false;

  }
  
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigandEpitopeAlignment::ListLigandEpitopeAlignment () {
  
  this->filenameIn              = new String () ;
  this->filenameOut             = new String ();
  this->ligandEpitopeAlignments = new TListE <LigandEpitopeAlignment> ();
  
  this->filenameSMI             = new String ();
  this->ligandNames             = new TListE <String> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigandEpitopeAlignment::ListLigandEpitopeAlignment (const ListLigandEpitopeAlignment& listLigandEpitopeAlignment) {
  
  this->filenameIn              = new String (listLigandEpitopeAlignment.filenameIn) ;
  this->filenameOut             = new String (listLigandEpitopeAlignment.filenameOut);
  this->ligandEpitopeAlignments = new TListE <LigandEpitopeAlignment> (listLigandEpitopeAlignment.ligandEpitopeAlignments);
  
  this->filenameSMI             = new String (listLigandEpitopeAlignment.filenameSMI);
  this->ligandNames             = new TListE <String> (listLigandEpitopeAlignment.ligandNames);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigandEpitopeAlignment::ListLigandEpitopeAlignment (const ListLigandEpitopeAlignment* listLigandEpitopeAlignment) {
  
  this->filenameIn              = new String (listLigandEpitopeAlignment->filenameIn) ;
  this->filenameOut             = new String (listLigandEpitopeAlignment->filenameOut);
  this->ligandEpitopeAlignments = new TListE <LigandEpitopeAlignment> (listLigandEpitopeAlignment->ligandEpitopeAlignments);
  
  this->filenameSMI             = new String (listLigandEpitopeAlignment->filenameSMI);
  this->ligandNames             = new TListE <String> (listLigandEpitopeAlignment->ligandNames);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigandEpitopeAlignment::~ListLigandEpitopeAlignment () {
  
  if (this->filenameIn)               delete this->filenameIn;
  if (this->filenameOut)              delete this->filenameOut;
  if (this->ligandEpitopeAlignments)  delete this->ligandEpitopeAlignments;
  if (this->filenameSMI)              delete this->filenameSMI;
  if (this->ligandNames)              delete this->ligandNames;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListLigandEpitopeAlignment::FilenameIn (String* filenameIn) {
  
  if (filenameIn) this->filenameIn->In(filenameIn);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListLigandEpitopeAlignment::FilenameOut (String* filenameOut) {
  
  if (filenameOut) this->filenameOut->In(filenameOut);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListLigandEpitopeAlignment::LigandEpitopeAlignments (TListE <LigandEpitopeAlignment>* LigandEpitopeAlignments) {
  
  if (ligandEpitopeAlignments) *(this->ligandEpitopeAlignments) = *(ligandEpitopeAlignments);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListLigandEpitopeAlignment::FilenameSMI (String* filenameSMI) {
  
  if (filenameSMI) this->filenameSMI->In(filenameSMI);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ListLigandEpitopeAlignment::LigandNames (TListE <String>* ligandNames) {
  
  if (ligandNames) *(this->ligandNames) = *(ligandNames);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListLigandEpitopeAlignment::FilenameIn (void) {
  
  return this->filenameIn;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListLigandEpitopeAlignment::FilenameOut (void) {
  
  return this->filenameOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <LigandEpitopeAlignment>* ListLigandEpitopeAlignment::LigandEpitopeAlignments (void) {
  
  return this->ligandEpitopeAlignments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ListLigandEpitopeAlignment::FilenameSMI (void) {
  
  return this->filenameSMI;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* ListLigandEpitopeAlignment::LigandNames (void) {
  
  return this->ligandNames;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListLigandEpitopeAlignment::LoadDataLigandEpitopeAligment (void) {
  
  if (!this->filenameIn || !this->filenameIn->Length()) return false;

  bool isGZFile = (this->filenameIn->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];
  
  if (isGZFile) { 
    zipFile = gzopen (this->filenameIn->Out(), "rb9"); 
    if (!zipFile) return false;
  }
  else {
    file.open (this->filenameIn->Out(), fstream::in);
    if (!file.is_open()) return false;
  }

  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, LENGTHTEXT);
    else          file.getline(buffer, LENGTHTEXT);
    
    if (!strlen(buffer)) continue;

    LigandEpitopeAlignment* newLigandEpitopeAlignment = new LigandEpitopeAlignment ();

    if (newLigandEpitopeAlignment->LoadData(buffer)) this->ligandEpitopeAlignments->Add(newLigandEpitopeAlignment);
    else                                             delete newLigandEpitopeAlignment;

  }

  if (isGZFile) gzclose(zipFile);
  else          file.close();

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListLigandEpitopeAlignment::LoadDataSMI (void) {
  
  if (!this->filenameSMI || !this->filenameSMI->Length()) return false;

  bool isGZFile = (this->filenameSMI->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];
  
  if (isGZFile) { 
    zipFile = gzopen (this->filenameSMI->Out(), "rb9"); 
    if (!zipFile) return false;
  }
  else {
    file.open (this->filenameSMI->Out(), fstream::in);
    if (!file.is_open()) return false;
  }
  
  int counter = 0;

  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, LENGTHTEXT);
    else          file.getline(buffer, LENGTHTEXT);
    
    if (!strlen(buffer)) continue;

    char* part = NULL;
    
    part = strtok(buffer, " \t\r\n"); if (!part) continue;
    part = strtok(NULL,   " \t\r\n"); if (!part) continue;

    this->ligandNames->Add(new String (part));

  }

  if (isGZFile) gzclose(zipFile);
  else          file.close();

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListLigandEpitopeAlignment::WriteMatrixEpitopeAligment (void) {
  
  if (!this->filenameOut             || !this->filenameOut->Length() ||
      !this->ligandNames             || !this->ligandNames->Length() ||
      !this->ligandEpitopeAlignments || !this->ligandEpitopeAlignments->Length())
    return false;
  
  bool isGZFile = (this->filenameOut->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];
  
  if (isGZFile) { 
    zipFile = gzopen (this->filenameOut->Out(), "wb9"); 
    if (!zipFile) return false;
  }
  else {
    file.open (this->filenameOut->Out(), fstream::out);
    if (!file.is_open()) return false;
  }
  
  for (long i = 0; i < this->ligandNames->Length(); i++) {
    
    sprintf(buffer, "%8s \0", this->ligandNames->Get(i)->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s", buffer);
    else          file << buffer;
    
  }
  
  if (isGZFile) gzprintf(zipFile, "\n", buffer);
  else          file << endl;

  PairWise pairwise;
  
  for (long i = 0; i < this->ligandNames->Length(); i++) {
    
    pairwise.ligand1 = this->ligandNames->Get(i);
    
    cout << i + 1 << "  " << pairwise.ligand1->Out() << endl;
    
    for (long j = 0; j < this->ligandNames->Length(); j++) {
      
      pairwise.ligand2 = this->ligandNames->Get(j);

      LigandEpitopeAlignment* searchLigandEpitopeAligment = this->ligandEpitopeAlignments->FirstOcurrence(LigandEpitopeSpace::EqualPairWiseLigand, &pairwise);
      
      if (searchLigandEpitopeAligment) sprintf(buffer, "%8.3f \0", searchLigandEpitopeAligment->HighEpitopeAlignment());
      else                             sprintf(buffer, "-100.000 \0");
      
      if (isGZFile) gzprintf(zipFile, "%s", buffer);
      else          file << buffer;
      
    }
    
    if (isGZFile) gzprintf(zipFile, "\n", buffer);
    else          file << endl;
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ListLigandEpitopeAlignment::WriteMatrixEpitopeAverageAligment (void) {
  
  if (!this->filenameOut             || !this->filenameOut->Length() ||
      !this->ligandNames             || !this->ligandNames->Length() ||
      !this->ligandEpitopeAlignments || !this->ligandEpitopeAlignments->Length())
    return false;
  
  bool isGZFile = (this->filenameOut->Contain("gz"))?1:0;

  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];
  
  if (isGZFile) { 
    zipFile = gzopen (this->filenameOut->Out(), "wb9"); 
    if (!zipFile) return false;
  }
  else {
    file.open (this->filenameOut->Out(), fstream::out);
    if (!file.is_open()) return false;
  }
  
  for (long i = 0; i < this->ligandNames->Length(); i++) {
    
    sprintf(buffer, "%8s \0", this->ligandNames->Get(i)->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s", buffer);
    else          file << buffer;
    
  }
  
  if (isGZFile) gzprintf(zipFile, "\n", buffer);
  else          file << endl;

  PairWise pairwise;
  
  for (long i = 0; i < this->ligandNames->Length(); i++) {
    
    pairwise.ligand1 = this->ligandNames->Get(i);
    
    cout << i + 1 << "  " << pairwise.ligand1->Out() << endl;
    
    for (long j = 0; j < this->ligandNames->Length(); j++) {
      
      pairwise.ligand2 = this->ligandNames->Get(j);

      LigandEpitopeAlignment* searchLigandEpitopeAligment = this->ligandEpitopeAlignments->FirstOcurrence(LigandEpitopeSpace::EqualPairWiseLigand, &pairwise);
      
      if (searchLigandEpitopeAligment) sprintf(buffer, "%8.3f \0", searchLigandEpitopeAligment->AverageEpitopeAlignment());
      else                             sprintf(buffer, "-100.000 \0");
      
      if (isGZFile) gzprintf(zipFile, "%s", buffer);
      else          file << buffer;
      
    }
    
    if (isGZFile) gzprintf(zipFile, "\n", buffer);
    else          file << endl;
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ListLigandEpitopeAlignment ListLigandEpitopeAlignment::operator= (const ListLigandEpitopeAlignment& listLigandEpitopeAlignment) {
  
  this->filenameIn->In(listLigandEpitopeAlignment.filenameIn) ;
  this->filenameOut->In(listLigandEpitopeAlignment.filenameOut);
  this->filenameSMI->In(listLigandEpitopeAlignment.filenameSMI);

  *(this->ligandEpitopeAlignments) = *(listLigandEpitopeAlignment.ligandEpitopeAlignments);
  *(this->ligandNames)             = *(listLigandEpitopeAlignment.ligandNames);
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
